#include "remote/control/controlsession.h"
#include "remote/base/basedefines.h"

namespace remote {
ControlSession::ControlSession(boost::asio::io_service &io_service,
                               vzconn::VzConnect::Ptr tcp_connect)
  : io_service_(io_service),
    tcp_connect_(tcp_connect) {

}

ControlSession::~ControlSession() {
}


bool ControlSession::StartSession() {
  BOOST_ASSERT(tcp_connect_);

  remote_addr_ = tcp_connect_->ip_addr();
  BOOST_ASSERT(!remote_addr_.empty());

  tcp_connect_->SignalConnectError.connect(
    boost::bind(&ControlSession::OnConnectError,
                shared_from_this(), _1, _2));
  tcp_connect_->SignalConnectWrite.connect(
    boost::bind(&ControlSession::OnConnectWrite,
                shared_from_this(), _1));
  tcp_connect_->SignalConnectRead.connect(
    boost::bind(&ControlSession::OnConnectRead,
                shared_from_this(), _1, _2, _3, _4));
  return true;
}

void ControlSession::StopSession() {
  tcp_connect_->CloseConnect();
}

void ControlSession::OnConnectError(vzconn::VzConnect::Ptr connect,
                                    const boost::system::error_code& err) {
}

void ControlSession::OnConnectWrite(vzconn::VzConnect::Ptr connect) {
}

void ControlSession::OnConnectRead(vzconn::VzConnect::Ptr connect,
                                   const char* buffer, int size, int flag) {
  // Handle Ping message
  if(flag == FLAG_PING_MESSAGE && size == 1) {
    connect->AsyncWrite(PING_MESSAGE, 1, FLAG_PING_MESSAGE);
    return;
  }
  QueryStanza::Ptr stanza(new QueryStanza);
  if(!stanza->Parse(buffer, size)) {
    LOG(ERROR) << "Failure to parse query stanza";
    return ;
  }
  if(flag == FLAG_REGISTER_MESSAGE) {
    ProcessRegister(connect, stanza);
  }
  if(session_name_.empty()) {
    LOG(ERROR) << "The session name is null, you can't send more message";
    return;
  }
  SignalSessionEvent(shared_from_this(), stanza);
}

void ControlSession::ProcessRegister(vzconn::VzConnect::Ptr connect,
                                     QueryStanza::Ptr stanza) {
  if(stanza->type() != JSON_TYPE_REGISTER) {
    LOG(ERROR) << "The type is not register";
    return;
  }
  std::string username = stanza->body()[JSON_USERNAME].asString();
  std::string password = stanza->body()[JSON_PASSWORD].asString();
  session_name_   = username + "@";
  session_name_   += remote_addr_;

  bool res = false;
  SignalRegisterEvent(shared_from_this(), &res);

  QueryStanza::Ptr response(new QueryStanza);
  response->set_type(JSON_TYPE_REGISTER);
  response->set_to(session_name_);
  response->set_from(DEFAULT_SERVER_NAME);
  response->set_id(stanza->id());
  if(res) {
    response->set_state(STATE_CONTROL_REGISTER_SUCCEED);
    connect->AsyncWrite(response->ToByteBuffer(), FLAG_REGISTER_MESSAGE);
  } else {
    response->set_state(STATE_CONTROL_REGISTER_FAILURE);
    connect->AsyncWrite(response->ToByteBuffer(), FLAG_REGISTER_MESSAGE);
    connect->CloseConnect();
  }
}

bool ControlSession::AsyncWrite(QueryStanza::Ptr stanza) {
  BOOST_ASSERT(tcp_connect_);
  return tcp_connect_->AsyncWrite(stanza->ToByteBuffer(), FLAG_NORMAL_MESSAGE);
}

}